package org.yaac.server.service;

import static com.google.common.collect.Lists.newLinkedList;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;

import org.yaac.client.service.BlobService;
import org.yaac.shared.ErrorCode;
import org.yaac.shared.SharedConstants.Blobstore;
import org.yaac.shared.YaacException;
import org.yaac.shared.blob.BlobInfoDTO;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.SortPredicate;
import com.googlecode.gql4j.GqlQuery;

/**
 * @author Max Zhu (thebbsky@gmail.com)
 * 
 */
public class BlobServiceImpl implements BlobService {

	private final Logger logger;
	
	@Inject
	BlobServiceImpl(Logger logger) {
		super();
		this.logger = logger;
	}

	@Override
	public List<BlobInfoDTO> load(String filterStr) throws YaacException {
		// step 1 : parse query
		String strQuery = "select * from " + Blobstore.BLOB_INFO_KIND + " " + filterStr;
		GqlQuery gql = new GqlQuery(strQuery);
		Query query = gql.query();
		
		logger.info("loading blobs, filter = " + filterStr);
		logger.info("parsed query = " + strQuery);
		
		// step 2 : validate query
		for (FilterPredicate filter : query.getFilterPredicates()) {
			if (! Blobstore.BLOB_INFO_ALL_PROPERTIES.contains(filter.getPropertyName())) {
				throw new YaacException(ErrorCode.E201, null);
			}
		}
		
		for (SortPredicate sort : query.getSortPredicates()) {
			if (! Blobstore.BLOB_INFO_ALL_PROPERTIES.contains(sort.getPropertyName())) {
				throw new YaacException(ErrorCode.E201, null);
			}
		}
		
		// step3 : execute query
		AsyncDatastoreService datastore = DatastoreServiceFactory.getAsyncDatastoreService();
		Iterable<Entity> entities = datastore.prepare(gql.query()).asIterable(gql.fetchOptions());
		
		List<BlobInfoDTO> result = newLinkedList();
		for (Entity e : entities) {
			result.add(new BlobInfoDTO(e.getKey().getName(),
			          (Date) e.getProperty(Blobstore.BLOB_INFO_CREATION),
			          (String) e.getProperty(Blobstore.BLOB_INFO_CONTENT_TYPE),
			          (String) e.getProperty(Blobstore.BLOB_INFO_FILENAME),
			          (Long) e.getProperty(Blobstore.BLOB_INFO_SIZE),
			          (String) e.getProperty(Blobstore.BLOB_INFO_MD5_HASH)));
		}
		
		return result;
	}

	@Override
	public void delete(Collection<String> blobKeyStrs) throws YaacException {
		BlobstoreService blobstore = BlobstoreServiceFactory.getBlobstoreService();
		
		BlobKey [] keys = new BlobKey[blobKeyStrs.size()];
		
		int i = 0;
		for (String blobKeyStr : blobKeyStrs) {
			keys[i++] = new BlobKey(blobKeyStr);
		}
		
		blobstore.delete(keys);
	}
}
